#include "L2CDTPServer.hpp"
#include <string.h>

using namespace L2CDTP;

Server::Server(SystemAdapter *system_adapter,SendCallback send_callback){
    this->system_adapter = system_adapter;
    this->send_callback = send_callback;
}

Server::~Server(){ }

void Server::processRequest(char *buffer,unsigned int size){
    if ( this->system_adapter == nullptr ) return;
    if ( this->send_callback == nullptr ) return;
    FrameHeader_t *request_header = (FrameHeader_t*)buffer;
    const char *label = (const char*)(buffer + sizeof(FrameHeader_t));
    const char *data = (const char*)(label + request_header->label_length);
    if ( request_header->type == TYPE_COMMAND ){
        CommandRequest_t command_request;
        CommandResponse_t command_response;
        memset(&command_request,0,sizeof(CommandRequest_t));
        memset(&command_response,0,sizeof(CommandResponse_t));
        command_request.extra_data = request_header->extra;
        command_request.command_label = label;
        command_request.bundle_data = data;
        command_request.bundle_data_size = request_header->data_length;
        bool status = this->system_adapter->executeCommand(command_request,&command_response);
        /* Build response header. */
        FrameHeader_t response_header;
        response_header.type = request_header->type;
        response_header.flag = (status ? FLAG_SUCCESS : FLAG_FAILED);
        response_header.extra = command_response.extra_data;
        response_header.label_length = request_header->label_length;
        response_header.data_length = command_response.bundle_data_size;

        unsigned int response_frame_length = sizeof(FrameHeader_t) + request_header->label_length + command_response.bundle_data_size;
        char response_buffer[response_frame_length];
        memset(response_buffer,0,response_frame_length);
        memcpy(response_buffer,&response_header,sizeof(FrameHeader_t));
        memcpy(response_buffer + sizeof(FrameHeader_t),label,request_header->label_length);
        memcpy(response_buffer + sizeof(FrameHeader_t) + request_header->label_length,command_response.bundle_data,command_response.bundle_data_size);
        
        this->send_callback(response_buffer,response_frame_length);

    }else if ( request_header->type == TYPE_DATA ){
        DataRequest_t data_request;
        DataResponse_t data_response;
        memset(&data_request,0,sizeof(DataRequest_t));
        memset(&data_response,0,sizeof(DataResponse_t));
        data_request.type = request_header->flag & FLAG_DATATYPE_MASK;
        data_request.rw = request_header->flag & FLAG_RW_MASK;
        data_request.extra_data = request_header->extra;
        data_request.data_label = label;
        data_request.data = data;
        data_request.data_size = request_header->data_length;

        bool status = this->system_adapter->accessData(data_request,&data_response);
        /* Build response header. */
        FrameHeader_t response_header;
        response_header.type = request_header->type;
        response_header.flag = (status ? FLAG_SUCCESS : FLAG_FAILED);
        response_header.extra = data_response.extra_data;
        response_header.label_length = request_header->label_length;
        response_header.data_length = data_response.data_size;

        unsigned int response_frame_length = sizeof(FrameHeader_t) + request_header->label_length + data_response.data_size;
        char response_buffer[response_frame_length];
        memset(response_buffer,0,response_frame_length);
        memcpy(response_buffer,&response_header,sizeof(FrameHeader_t));
        memcpy(response_buffer + sizeof(FrameHeader_t),label,request_header->label_length);
        memcpy(response_buffer + sizeof(FrameHeader_t) + request_header->label_length,data_response.data,data_response.data_size);

        this->send_callback(response_buffer,response_frame_length);

    }else{
        return;
    }
}